package com.dycong.common.leetcode;

/**
 * 作用描述: 加油站
 * <p>
 * 题目描述
 * 评论 (126)
 * 题解(50)
 * 提交记录
 * 在一条环路上有 N 个加油站，其中第 i 个加油站有汽油 gas[i] 升。
 * <p>
 * 你有一辆油箱容量无限的的汽车，从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发，开始时油箱为空。
 * <p>
 * 如果你可以绕环路行驶一周，则返回出发时加油站的编号，否则返回 -1。
 * <p>
 * 说明:
 * <p>
 * 如果题目有解，该答案即为唯一答案。
 * 输入数组均为非空数组，且长度相同。
 * 输入数组中的元素均为非负数。
 * 示例 1:
 * <p>
 * 输入:
 * gas  = [1,2,3,4,5]
 * cost = [3,4,5,1,2]
 * <p>
 * 输出: 3
 * <p>
 * 解释:
 * 从 3 号加油站(索引为 3 处)出发，可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油
 * 开往 4 号加油站，此时油箱有 4 - 1 + 5 = 8 升汽油
 * 开往 0 号加油站，此时油箱有 8 - 2 + 1 = 7 升汽油
 * 开往 1 号加油站，此时油箱有 7 - 3 + 2 = 6 升汽油
 * 开往 2 号加油站，此时油箱有 6 - 4 + 3 = 5 升汽油
 * 开往 3 号加油站，你需要消耗 5 升汽油，正好足够你返回到 3 号加油站。
 * 因此，3 可为起始索引。
 * 示例 2:
 * <p>
 * 输入:
 * gas  = [2,3,4]
 * cost = [3,4,3]
 * <p>
 * 输出: -1
 * <p>
 * 解释:
 * 你不能从 0 号或 1 号加油站出发，因为没有足够的汽油可以让你行驶到下一个加油站。
 * 我们从 2 号加油站出发，可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油
 * 开往 0 号加油站，此时油箱有 4 - 3 + 2 = 3 升汽油
 * 开往 1 号加油站，此时油箱有 3 - 3 + 3 = 3 升汽油
 * 你无法返回 2 号加油站，因为返程需要消耗 4 升汽油，但是你的油箱只有 3 升汽油。
 * 因此，无论怎样，你都不可能绕环路行驶一周。
 *
 * @author dycong
 * @date 2019/12/24 9:12
 */
public class CanCompleteCircuit_134 {
    public static void main(String[] args) {
        CanCompleteCircuit_134 canCompleteCircuit_134 = new CanCompleteCircuit_134();
        int[] gas = new int[]{1, 2, 3, 4, 5};
        int[] cost = new int[]{3, 4, 5, 1, 2};
        System.out.println(canCompleteCircuit_134.canCompleteCircuit1(gas, cost));
    }


    public int canCompleteCircuit(int[] gas, int[] cost) {
        int length = gas.length;
        for (int i = 0; i < length; i++) {
            int leftGas = 0;
            for (int j = i, k = 0; k < length; k++, j++) {
                if (j >= length) {
                    j -= length;
                }
                leftGas += (gas[j] - cost[j]);
                if (leftGas < 0) {
                    break;
                }
            }
            if (leftGas >= 0) {
                return i;
            }
        }

        return -1;
    }

    /**
     * 优化
     * 1.如果 sum(gas) < sum(cost) ，那么不可能环行一圈，这种情况下答案是 -1 。
     * 2.对于加油站 i ，如果 gas[i] - cost[i] < 0 ，则不可能从这个加油站出发，因为在前往 i + 1 的过程中，汽油就不够了。
     *
     * @param gas
     * @param cost
     * @return
     */
    public int canCompleteCircuit0(int[] gas, int[] cost) {
        int length = gas.length;
        for (int i = 0; i < length; i++) {
            //对于加油站 i ，如果 gas[i] - cost[i] < 0 ，则不可能从这个加油站出发，因为在前往 i + 1 的过程中，汽油就不够了。
            if (gas[i] < cost[i]) {
                continue;
            }
            int leftGas = 0;
            for (int j = i, k = 0; k < length; k++, j++) {
                if (j >= length) {
                    j -= length;
                }
                leftGas += (gas[j] - cost[j]);
                if (leftGas < 0) {
                    break;
                }
            }
            if (leftGas >= 0) {
                return i;
            }
        }
        return 0;
    }

    /**
     * 一次遍历法，车能开完全程需要满足两个条件：
     * <p>
     * 车从i站能开到i+1。
     * <p>
     * 所有站里的油总量要>=车子的总耗油量。
     * <p>
     * 那么，假设从编号为0站开始，一直到k站都正常，在开往k+1站时车子没油了。这时，应该将起点设置为k+1站。
     * <p>
     * 问题1: 为什么应该将起始站点设为k+1？
     * <p>
     * 因为k->k+1站耗油太大，0->k站剩余油量都是不为负的，每减少一站，就少了一些剩余油量。所以如果从k前面的站点作为起始站，剩余油量不可能冲过k+1站。
     * 问题2: 为什么如果k+1->end全部可以正常通行，且rest>=0就可以说明车子从k+1站点出发可以开完全程？
     * <p>
     * 因为，起始点将当前路径分为A、B两部分。其中，必然有(1)A部分剩余油量<0。(2)B部分剩余油量>0。
     * <p>
     * 所以，无论多少个站，都可以抽象为两个站点（A、B）。(1)从B站加满油出发，(2)开往A站，车加油，(3)再开回B站的过程。
     * <p>
     * 重点：B剩余的油>=A缺少的总油。必然可以推出，B剩余的油>=A站点的每个子站点缺少的油。
     *
     * @param gas
     * @param cost
     * @return
     */
    public int canCompleteCircuit1(int[] gas, int[] cost) {
        int n = gas.length;

        int totalTank = 0, currentTank = 0, startPosition = 0;

        for (int i = 0; i < n; i++) {
            totalTank += (gas[i] - cost[i]);
            currentTank = currentTank + gas[i] - cost[i];

            if (currentTank < 0) {
                currentTank = 0;
                startPosition = i + 1;
            }
        }
        return totalTank >= 0 ? startPosition : -1;
    }

    /*
    int n = gas.length;
        int total_tank = 0;
        int curr_tank = 0;
        int starting_station = 0;
        for (int i = 0; i < n; ++i) {
            total_tank += gas[i] - cost[i];
            curr_tank += gas[i] - cost[i];
            // If one couldn't get here,
            if (curr_tank < 0) {
                // Pick up the next station as the starting one.
                starting_station = i + 1;
                // Start with an empty tank.
                curr_tank = 0;
            }
        }
        return total_tank >= 0 ? starting_station : -1;
     */

}
